package com.example.rssreader.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.rssreader.common.PageResponse;
import com.example.rssreader.dto.ArticleResponse;
import com.example.rssreader.entity.Article;
import com.example.rssreader.entity.RssFeed;
import com.example.rssreader.mapper.ArticleMapper;
import com.example.rssreader.mapper.RssFeedMapper;
import com.example.rssreader.service.ArticleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 文章服务实现类
 * 实现文章相关的业务逻辑
 * 
 * @author RSS Reader Team
 * @version 1.0.0
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ArticleServiceImpl implements ArticleService {

    private final ArticleMapper articleMapper;
    private final RssFeedMapper rssFeedMapper;

    /**
     * 分页查询文章列表
     * 
     * @param page   页码，从1开始
     * @param size   每页大小
     * @param feedId RSS源ID，可选参数，为null时查询所有RSS源的文章
     * @param isRead 是否已读，可选参数，为null时查询所有状态的文章
     * @return 分页响应结果
     */
    @Override
    public PageResponse<ArticleResponse> getArticles(Integer page, Integer size, Long feedId, Boolean isRead) {
        log.debug("分页查询文章列表，页码: {}, 每页大小: {}, RSS源ID: {}, 是否已读: {}", page, size, feedId, isRead);
        
        try {
            Page<Article> pageParam = new Page<>(page, size);
            Page<Article> result = (Page<Article>) articleMapper.selectArticlePage(pageParam, feedId, isRead);
            
            List<ArticleResponse> responses = result.getRecords().stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());
            
            return PageResponse.of(responses, result.getTotal(), page, size);
            
        } catch (Exception e) {
            log.error("查询文章列表失败: {}", e.getMessage(), e);
            throw new RuntimeException("查询文章列表失败: " + e.getMessage());
        }
    }

    /**
     * 根据ID获取文章详情
     * 包含完整的文章内容
     * 
     * @param id 文章ID
     * @return 文章响应信息
     * @throws RuntimeException 当文章不存在时抛出异常
     */
    @Override
    public ArticleResponse getArticleById(Long id) {
        log.debug("根据ID获取文章详情，ID: {}", id);
        
        try {
            Article article = articleMapper.selectById(id);
            if (article == null || article.getDeleted() != 0) {
                log.warn("文章不存在，ID: {}", id);
                throw new RuntimeException("文章不存在");
            }
            
            return convertToResponse(article);
            
        } catch (Exception e) {
            log.error("获取文章详情失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("获取文章详情失败: " + e.getMessage());
        }
    }

    /**
     * 标记文章为已读
     * 
     * @param id 文章ID
     * @throws RuntimeException 当文章不存在时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markAsRead(Long id) {
        log.debug("标记文章为已读，ID: {}", id);
        
        try {
            Article article = articleMapper.selectById(id);
            if (article == null || article.getDeleted() != 0) {
                log.warn("文章不存在，ID: {}", id);
                throw new RuntimeException("文章不存在");
            }
            
            LambdaUpdateWrapper<Article> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Article::getId, id)
                    .set(Article::getIsRead, true);
            
            articleMapper.update(null, updateWrapper);
            log.debug("文章标记为已读成功，ID: {}", id);
            
        } catch (Exception e) {
            log.error("标记文章为已读失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("标记文章为已读失败: " + e.getMessage());
        }
    }

    /**
     * 标记文章为未读
     * 
     * @param id 文章ID
     * @throws RuntimeException 当文章不存在时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markAsUnread(Long id) {
        log.debug("标记文章为未读，ID: {}", id);
        
        try {
            Article article = articleMapper.selectById(id);
            if (article == null || article.getDeleted() != 0) {
                log.warn("文章不存在，ID: {}", id);
                throw new RuntimeException("文章不存在");
            }
            
            LambdaUpdateWrapper<Article> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Article::getId, id)
                    .set(Article::getIsRead, false);
            
            articleMapper.update(null, updateWrapper);
            log.debug("文章标记为未读成功，ID: {}", id);
            
        } catch (Exception e) {
            log.error("标记文章为未读失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("标记文章为未读失败: " + e.getMessage());
        }
    }

    /**
     * 批量标记文章为已读
     * 
     * @param articleIds 文章ID列表
     * @return 成功标记的文章数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer batchMarkAsRead(List<Long> articleIds) {
        log.info("批量标记文章为已读，文章数量: {}", articleIds.size());
        
        try {
            if (articleIds.isEmpty()) {
                return 0;
            }
            
            int updatedCount = articleMapper.batchMarkAsRead(articleIds);
            log.info("批量标记文章为已读成功，更新数量: {}", updatedCount);
            
            return updatedCount;
            
        } catch (Exception e) {
            log.error("批量标记文章为已读失败: {}", e.getMessage(), e);
            throw new RuntimeException("批量标记文章为已读失败: " + e.getMessage());
        }
    }

    /**
     * 标记RSS源下所有文章为已读
     * 
     * @param feedId RSS源ID
     * @return 成功标记的文章数量
     * @throws RuntimeException 当RSS源不存在时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer markFeedArticlesAsRead(Long feedId) {
        log.info("标记RSS源下所有文章为已读，RSS源ID: {}", feedId);
        
        try {
            // 检查RSS源是否存在
            RssFeed feed = rssFeedMapper.selectById(feedId);
            if (feed == null || feed.getDeleted() != 0) {
                log.warn("RSS源不存在，ID: {}", feedId);
                throw new RuntimeException("RSS源不存在");
            }
            
            int updatedCount = articleMapper.markFeedArticlesAsRead(feedId);
            log.info("标记RSS源文章为已读成功，RSS源ID: {}, 更新数量: {}", feedId, updatedCount);
            
            return updatedCount;
            
        } catch (Exception e) {
            log.error("标记RSS源文章为已读失败，RSS源ID: {}, 错误: {}", feedId, e.getMessage(), e);
            throw new RuntimeException("标记RSS源文章为已读失败: " + e.getMessage());
        }
    }

    /**
     * 搜索文章
     * 根据关键词在标题、描述和内容中进行模糊搜索
     * 
     * @param keyword 搜索关键词
     * @param page    页码，从1开始
     * @param size    每页大小
     * @param feedId  RSS源ID，可选参数，为null时在所有RSS源中搜索
     * @return 分页响应结果
     */
    @Override
    public PageResponse<ArticleResponse> searchArticles(String keyword, Integer page, Integer size, Long feedId) {
        log.debug("搜索文章，关键词: {}, 页码: {}, 每页大小: {}, RSS源ID: {}", keyword, page, size, feedId);
        
        try {
            Page<Article> pageParam = new Page<>(page, size);
            Page<Article> result = (Page<Article>) articleMapper.searchArticles(pageParam, keyword, feedId);
            
            List<ArticleResponse> responses = result.getRecords().stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());
            
            return PageResponse.of(responses, result.getTotal(), page, size);
            
        } catch (Exception e) {
            log.error("搜索文章失败，关键词: {}, 错误: {}", keyword, e.getMessage(), e);
            throw new RuntimeException("搜索文章失败: " + e.getMessage());
        }
    }

    /**
     * 获取未读文章数量
     * 
     * @param feedId RSS源ID，可选参数，为null时统计所有RSS源的未读文章
     * @return 未读文章数量
     */
    @Override
    public Long getUnreadCount(Long feedId) {
        log.debug("获取未读文章数量，RSS源ID: {}", feedId);
        
        try {
            return articleMapper.countUnreadArticles(feedId);
        } catch (Exception e) {
            log.error("获取未读文章数量失败，RSS源ID: {}, 错误: {}", feedId, e.getMessage(), e);
            throw new RuntimeException("获取未读文章数量失败: " + e.getMessage());
        }
    }

    /**
     * 获取最新文章
     * 
     * @param limit 限制数量，默认10条
     * @return 最新文章列表
     */
    @Override
    public List<ArticleResponse> getLatestArticles(Integer limit) {
        log.debug("获取最新文章，限制数量: {}", limit);
        
        try {
            if (limit == null || limit <= 0) {
                limit = 10;
            }
            
            List<Article> articles = articleMapper.selectLatestArticles(limit);
            return articles.stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());
            
        } catch (Exception e) {
            log.error("获取最新文章失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取最新文章失败: " + e.getMessage());
        }
    }

    /**
     * 删除文章
     * 逻辑删除
     * 
     * @param id 文章ID
     * @throws RuntimeException 当文章不存在时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteArticle(Long id) {
        log.info("删除文章，ID: {}", id);
        
        try {
            Article article = articleMapper.selectById(id);
            if (article == null || article.getDeleted() != 0) {
                log.warn("文章不存在，ID: {}", id);
                throw new RuntimeException("文章不存在");
            }
            
            articleMapper.deleteById(id);
            log.info("文章删除成功，ID: {}", id);
            
        } catch (Exception e) {
            log.error("删除文章失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("删除文章失败: " + e.getMessage());
        }
    }

    /**
     * 批量删除文章
     * 逻辑删除
     * 
     * @param articleIds 文章ID列表
     * @return 成功删除的文章数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer batchDeleteArticles(List<Long> articleIds) {
        log.info("批量删除文章，文章数量: {}", articleIds.size());
        
        try {
            if (articleIds.isEmpty()) {
                return 0;
            }
            
            int deletedCount = articleMapper.deleteBatchIds(articleIds);
            log.info("批量删除文章成功，删除数量: {}", deletedCount);
            
            return deletedCount;
            
        } catch (Exception e) {
            log.error("批量删除文章失败: {}", e.getMessage(), e);
            throw new RuntimeException("批量删除文章失败: " + e.getMessage());
        }
    }

    /**
     * 清理旧文章
     * 删除指定天数之前的文章
     * 
     * @param daysAgo 天数，删除多少天前的文章
     * @return 清理的文章数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer cleanOldArticles(Integer daysAgo) {
        log.info("清理旧文章，删除{}天前的文章", daysAgo);
        
        try {
            if (daysAgo == null || daysAgo <= 0) {
                throw new RuntimeException("天数参数无效");
            }
            
            LocalDateTime beforeTime = LocalDateTime.now().minusDays(daysAgo);
            int deletedCount = articleMapper.deleteArticlesBefore(beforeTime);
            
            log.info("清理旧文章成功，删除数量: {}", deletedCount);
            return deletedCount;
            
        } catch (Exception e) {
            log.error("清理旧文章失败: {}", e.getMessage(), e);
            throw new RuntimeException("清理旧文章失败: " + e.getMessage());
        }
    }

    /**
     * 获取文章统计信息
     * 
     * @param feedId RSS源ID，可选参数，为null时统计所有RSS源
     * @return 统计信息，包括总数、未读数量、今日新增等
     */
    @Override
    public Object getArticleStatistics(Long feedId) {
        log.debug("获取文章统计信息，RSS源ID: {}", feedId);
        
        try {
            Map<String, Object> statistics = new HashMap<>();
            
            // 总文章数量
            Long totalArticles = feedId != null ? 
                    articleMapper.countArticlesByFeed(feedId) : 
                    articleMapper.countUnreadArticles(null) + articleMapper.countUnreadArticles(null);
            statistics.put("totalArticles", totalArticles);
            
            // 未读文章数量
            Long unreadArticles = articleMapper.countUnreadArticles(feedId);
            statistics.put("unreadArticles", unreadArticles);
            
            // 已读文章数量
            statistics.put("readArticles", totalArticles - unreadArticles);
            
            // 最新文章
            List<Article> latestArticles = articleMapper.selectLatestArticles(5);
            statistics.put("latestArticles", latestArticles.stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList()));
            
            return statistics;
            
        } catch (Exception e) {
            log.error("获取文章统计信息失败，RSS源ID: {}, 错误: {}", feedId, e.getMessage(), e);
            throw new RuntimeException("获取文章统计信息失败: " + e.getMessage());
        }
    }

    /**
     * 标记所有文章为已读
     * 
     * @return 成功标记的文章数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer markAllAsRead() {
        log.info("标记所有文章为已读");
        
        try {
            LambdaUpdateWrapper<Article> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Article::getIsRead, false)
                    .eq(Article::getDeleted, false)
                    .set(Article::getIsRead, true);
            
            int updatedCount = articleMapper.update(null, updateWrapper);
            log.info("标记所有文章为已读成功，更新数量: {}", updatedCount);
            
            return updatedCount;
            
        } catch (Exception e) {
            log.error("标记所有文章为已读失败: {}", e.getMessage(), e);
            throw new RuntimeException("标记所有文章为已读失败: " + e.getMessage());
        }
    }

    /**
     * 将文章实体转换为响应DTO
     * 
     * @param article 文章实体
     * @return 文章响应DTO
     */
    private ArticleResponse convertToResponse(Article article) {
        ArticleResponse response = new ArticleResponse();
        response.setId(article.getId())
                .setTitle(article.getTitle())
                .setLink(article.getLink())
                .setDescription(article.getDescription())
                .setContent(article.getContent())
                .setAuthor(article.getAuthor())
                .setPublishedAt(LocalDateTime.parse(article.getPublishedAt()))
                .setIsRead(article.getIsRead());
        
        // 设置RSS源信息
        try {
            RssFeed feed = rssFeedMapper.selectById(article.getFeedId());
            if (feed != null) {
                ArticleResponse.FeedInfo feedInfo = new ArticleResponse.FeedInfo();
                feedInfo.setId(feed.getId())
                        .setTitle(feed.getTitle())
                        .setUrl(feed.getUrl());
                response.setFeed(feedInfo);
            }
        } catch (Exception e) {
            log.warn("获取文章RSS源信息失败，文章ID: {}, 错误: {}", article.getId(), e.getMessage());
        }
        
        return response;
    }
}